﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using URSA.Classes;
using URSA.Tools;

namespace URSA.GroundControl
{
    public partial class Gooey : Form
    {
        //Port used to connect to robot
        private URSAPort _port;

        //Sensors
        private AcceloMeter accelSense;     //Accelerometer
        private UltraSonics ultraSense;     //Ultrasonics
        private InfraLights infraSense;     //InfraRed LED
        
        
        
        // Enumeration of commands
        public enum CommandId : byte
        {
            GetNullEcho = 0,            //Ask for null Echo
            GetBoardStuff = 1,          //Ask for LED and Switch status
            SetBoardLEDs = 2,           //Set Board LEDS
            GetIntrnlCtr = 3,           //Ask for Board Internal Counter
            GetMotorStats = 4,          //Ask for Motor Status
            SetMotorVelL = 5,           //Set Left motor velocity
            SetMotorVelR = 6,           //Set Right motor velocity
            SetMotorVelT = 7,           //Set Turret motor velocity
            GetBumpStats = 8,           //Ask for bump sensor status
            GetSensorData = 9,          //Ask for built in sensor data
            GetUltraChannel = 10,       //Request specific ultrasonic channel
            GetUltraSndStat = 11,       //Ask for request ultrasonic wave status
            GetUltraSndData = 12,       //Ask for ultrasonic data
            SetUltraSndTrim = 13,       //Set value of ultrasonic freq trim
            SetLastUltraEcho = 16       //Send last ultrasonic echo detedt (WOT DOES THIS MEAN!?)
        }

        public Gooey()
        {
            InitializeComponent();
            ShiftWindow();
            InitialiseAcceloMeter();
            Utilities.OnError += new Utilities.ExceptionHandler(Helpers_OnError);
            return;
        }

        void ShiftWindow()
        {
            this.Location = new System.Drawing.Point(0, 0);
            return;
        }

        void InitialiseAcceloMeter()
        {
            double aOffset = 0, aRange = 1;
            double bOffset = 0, bRange = 1;
            double cOffset = 0, cRange = 1;
            accelSense = new AcceloMeter(aOffset, aRange, bOffset, bRange, cOffset, cRange);
            return;
        }
        void InitialiseUltraSonics()
        {
            return;
        }

        void Helpers_OnError(Exception error)
        {
            Console.WriteLine(error.Message);
            return;
        }

        private void _port_onMessageReceived(object sender, byte[] message)
        {
            /* This method is called in responce to the MessageReceived event being fired from within the URSAPort class.
             * The internal workings of the URSA port class are operating on a different thread to that of the GUI, we must therfore
             * invoke any code that changes the GUI in the same thread as the GUI, this is what 'this.BeginInvoke' does for us.
             * */
            this.BeginInvoke(new EventHandler(delegate
            {
                string stringRepresentation = Utilities.ConvertByteArrayToString(message);

                rtbMessages.AppendText(string.Format("{0}\n", stringRepresentation));

                // Ensure the message is not malformed
                if (message.Length >= 2)
                {
                    //Parse RSSI
                    labelRSSI.Text = message.GetValue(0).ToString();
                    progressBarRSSI.Value = int.Parse(message.GetValue(0).ToString());

                    CommandId command = (CommandId)message.GetValue(1); //Get type code

                    //Parse based on message type code
                    if (command == CommandId.GetIntrnlCtr && message.Length == 4)
                    {
                        labelRecvCount.Text = message.GetValue(2).ToString();
                    }
                    else
                    {
                        rtbMessages.AppendText(string.Format("Invalid message recieved (Type Code: {0}\n", command));
                    }
                }
            }));
        }

        private void timerGooeyUpdate_Tick(object sender, EventArgs e)
        {
            // Code to ensure buttons are only available when desired, based around the state of the port
			
			if (_port == null || !_port.isOpen)
			{
				buttonOpenPort.Visible = true;
			}
			else
			{
				buttonOpenPort.Visible = false;
			}

            panelControls.Enabled = buttonClosePort.Visible = !buttonOpenPort.Visible;
            return;
		}

        private void buttonOpenPort_Click(object sender, EventArgs e)
        {
            _port = Utilities.CreatePort();
			if (_port != null)
			{
				_port.OnMessageReceived += new URSAPort.MessageReceivedHandler(_port_onMessageReceived);
			}
            return;
        }

        private void buttonClosePort_Click(object sender, EventArgs e)
        {
            if (_port != null)
            {
                _port.Close();
            }
            return;
        }

        private void buttonExit_Click(object sender, EventArgs e)
        {
            this.Close();
            return;
        }

        private void buttonSetMotor_Click(object sender, EventArgs e)
        {
            byte lMotor, rMotor;
            if (numericUpDownLeft.Value >= 0)
            {
                lMotor = Decimal.ToByte(numericUpDownLeft.Value);
            }
            else
            {
                lMotor = Decimal.ToByte(256 - numericUpDownLeft.Value);
            }

            if (numericUpDownRight.Value >= 0)
            {
                rMotor = Decimal.ToByte(numericUpDownRight.Value);
            }
            else
            {
                rMotor = Decimal.ToByte(256 - numericUpDownRight.Value);
            }
            
            _port.SendData((byte)CommandId.SetMotorVelL, new byte[] { lMotor });
            _port.SendData((byte)CommandId.SetMotorVelR, new byte[] { rMotor });
            return;
        }

        private void buttonStopMotor_Click(object sender, EventArgs e)
        {
            _port.SendData((byte)CommandId.SetMotorVelL, new byte[] { 0x00 });
            _port.SendData((byte)CommandId.SetMotorVelR, new byte[] { 0x00 });
            return;
        }

    }
}